package cn.udesk.web.service;

import java.io.IOException;
import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import cn.hutool.core.date.DateUtil;
import cn.udesk.common.toolkit.Constant;
import cn.udesk.core.dto.BootTablePage;
import cn.udesk.core.mapper.KTransDao;
import cn.udesk.core.mapper.KTransMonitorDao;
import cn.udesk.core.model.KTrans;
import cn.udesk.core.model.KTransMonitor;
import cn.udesk.web.quartz.QuartzManager;
import cn.udesk.web.quartz.TransQuartz;
import cn.udesk.web.quartz.model.DBConnectionModel;
import cn.udesk.web.utils.CommonUtils;

@Service
public class TransService {

  @Autowired
  private KTransDao kTransDao;

  @Autowired
  private KTransMonitorDao kTransMonitorDao;

  @Value("${kettle.log.file.path}")
  private String kettleLogFilePath;

  @Value("${kettle.file.repository}")
  private String kettleFileRepository;

  @Value("${jdbc.driver}")
  private String jdbcDriver;

  @Value("${jdbc.url}")
  private String jdbcUrl;

  @Value("${jdbc.username}")
  private String jdbcUsername;

  @Value("${jdbc.password}")
  private String jdbcPassword;

  // 获取转换总数、转换成功数、转换失败数
  public Long getTransCount(Integer status) {
    KTrans template = new KTrans();
    if (status != null) {
      template.setTransStatus(status);
    }
    template.setDelFlag(Constant.NOT_DELETE);
    return kTransDao.templateCount(template);
  }

  /**
   * @Title getList
   * @Description 获取列表
   * @param uId 用户ID
   * @return
   * @return List<KTrans>
   */
  public List<KTrans> getList() {
    KTrans template = new KTrans();
    template.setDelFlag(Constant.NOT_DELETE);
    return kTransDao.template(template);
  }

  /**
   * @Title getList
   * @Description 获取列表
   * @param start 其实行数
   * @param size 获取数据的条数
   * @param uId 用户ID
   * @return
   * @return BootTablePage
   */
  public BootTablePage getList(Integer start, Integer size) {
    KTrans template = new KTrans();
    template.setDelFlag(Constant.NOT_DELETE);
    List<KTrans> kTransList = kTransDao.template(template, start, size);
    Long allCount = kTransDao.templateCount(template);
    BootTablePage bootTablePage = new BootTablePage();
    bootTablePage.setRows(kTransList);
    bootTablePage.setTotal(allCount);
    return bootTablePage;
  }

  /**
   * @Title delete
   * @Description 删除转换
   * @param kTransId 转换ID
   * @return void
   */
  public void delete(Integer kTransId) {
    KTrans kTrans = kTransDao.unique(kTransId);
    kTrans.setDelFlag(Constant.DELETED);
    kTransDao.updateById(kTrans);
  }

  /**
   * @Title check
   * @Description 检查转换是否添加过
   * @param repositoryId 资源库ID
   * @param kTransPath 转换路径信息
   * @param uId 用户ID
   * @return
   * @return boolean
   */
  public boolean check(String kTransPath, Integer uId) {
    KTrans template = new KTrans();
    template.setDelFlag(Constant.NOT_DELETE);
    template.setAddUser(uId);
    template.setTransPath(kTransPath);
    List<KTrans> kTransList = kTransDao.template(template);
    if (null != kTransList && kTransList.size() > 0) {
      return false;
    } else {
      return true;
    }
  }

  /**
   * @Title saveFile
   * @Description 保存上传的转换文件
   * @param uId 用户ID
   * @param transFile 需要保存的转换文件
   * @return
   * @throws IOException
   * @return String
   */
  public String saveFile(Integer uId, String uuid, MultipartFile transFile) throws IOException {
    return CommonUtils.saveFile(kettleFileRepository, uuid, transFile);
  }

  /**
   * @Title insert
   * @Description 添加转换到数据库
   * @param kTrans 转换对象
   * @param uId 用户ID
   * @param customerQuarz 用户自定义的定时策略
   * @throws SQLException
   * @return void
   */
  public void insert(KTrans kTrans, Integer uId) throws SQLException {
    kTrans.setAddTime(new Date());
    kTrans.setAddUser(uId);
    kTrans.setDelFlag(Constant.NOT_DELETE);
    kTrans.setTransStatus(Constant.TRANS_STOPED);
    kTransDao.insert(kTrans);
  }

  /**
   * @Title getTrans
   * @Description 获取转换对象
   * @param transId 转换ID
   * @return
   * @return KTrans
   */
  public KTrans getTrans(Integer transId) {
    return kTransDao.single(transId);
  }

  /**
   * @Title update
   * @Description 更新转换信息
   * @param kTrans 转换对象
   * @param uId 用户ID
   * @return void
   */
  public void update(KTrans kTrans, Integer uId) {
    kTrans.setEditTime(new Date());
    kTrans.setEditUser(uId);
    kTransDao.updateTemplateById(kTrans);

    kTrans = kTransDao.unique(kTrans.getTransId());
    if (kTrans.getTransStatus() != null && kTrans.getTransStatus().equals(Constant.TRANS_RUNNING)) {
      this.stop(kTrans.getTransId());
      this.start(kTrans.getTransId());
    }
  }

  /**
   * @Title start
   * @Description 启动转换
   * @param transId 转换ID
   * @return void
   */
  public void start(Integer transId) {
    // 获取到转换对象
    KTrans kTrans = kTransDao.unique(transId);
    // 定时策略
    String quartzCron = kTrans.getTransQuartz();
    // 用户ID
    Integer userId = kTrans.getAddUser();
    // 获取Quartz执行的基础信息
    Map<String, String> quartzBasic = getQuartzBasic(kTrans);
    // 获取Quartz的参数
    Map<String, Object> quartzParameter = getQuartzParameter(kTrans);
    // 添加监控
    addMonitor(userId, transId);
    // 添加任务
    // 判断转换执行类型
    // 如果是按照策略执行
    // 添加任务
    QuartzManager.addJob(quartzBasic.get("jobName"), quartzBasic.get("jobGroupName"),
        quartzBasic.get("triggerName"), quartzBasic.get("triggerGroupName"), TransQuartz.class,
        quartzCron, quartzParameter);
    kTrans.setTransStatus(1);
    kTransDao.updateTemplateById(kTrans);
  }

  /**
   * @Title stop
   * @Description 停止转换
   * @param transId 转换ID
   * @return void
   */
  public void stop(Integer transId) {
    // 获取到作业对象
    KTrans kTrans = kTransDao.unique(transId);
    // 用户ID
    Integer userId = kTrans.getAddUser();
    // 获取Quartz执行的基础信息
    Map<String, String> quartzBasic = getQuartzBasic(kTrans);
    // 移除任务
    // 如果是按照策略执行
    QuartzManager.removeJob(quartzBasic.get("jobName"), quartzBasic.get("jobGroupName"),
        quartzBasic.get("triggerName"), quartzBasic.get("triggerGroupName"));
    // 移除监控
    removeMonitor(userId, transId);
    // 更新任务状态
    kTrans.setTransStatus(2);
    kTransDao.updateTemplateById(kTrans);
  }

  /**
   * @Title getQuartzBasic
   * @Description 获取任务调度的基础信息
   * @param kTrans 转换对象
   * @return
   * @return Map<String, String> 任务调度的基础信息
   */
  private Map<String, String> getQuartzBasic(KTrans kTrans) {
    Integer userId = kTrans.getAddUser();
    String transPath = kTrans.getTransPath();
    Map<String, String> quartzBasic = new HashMap<String, String>();
    // 拼接Quartz的任务名称
    StringBuilder jobName = new StringBuilder();
    jobName.append(Constant.JOB_PREFIX).append(Constant.QUARTZ_SEPARATE).append(transPath);
    // 拼接Quartz的任务组名称
    StringBuilder jobGroupName = new StringBuilder();
    jobGroupName.append(Constant.JOB_GROUP_PREFIX).append(Constant.QUARTZ_SEPARATE).append(userId)
        .append(Constant.QUARTZ_SEPARATE).append(transPath);
    // 拼接Quartz的触发器名称
    String triggerName =
        StringUtils.replace(jobName.toString(), Constant.JOB_PREFIX, Constant.TRIGGER_PREFIX);
    // 拼接Quartz的触发器组名称
    String triggerGroupName = StringUtils.replace(jobGroupName.toString(),
        Constant.JOB_GROUP_PREFIX, Constant.TRIGGER_GROUP_PREFIX);
    quartzBasic.put("jobName", jobName.toString());
    quartzBasic.put("jobGroupName", jobGroupName.toString());
    quartzBasic.put("triggerName", triggerName);
    quartzBasic.put("triggerGroupName", triggerGroupName);
    return quartzBasic;
  }

  /**
   * @Title getQuartzParameter
   * @Description 获取任务调度的参数
   * @param kTrans 转换对象
   * @return
   * @return Map<String, Object>
   */
  private Map<String, Object> getQuartzParameter(KTrans kTrans) {
    // Quartz执行时的参数
    Map<String, Object> parameter = new HashMap<String, Object>();
    // 数据库连接对象
    parameter.put(Constant.DBCONNECTIONOBJECT,
        new DBConnectionModel(jdbcDriver, jdbcUrl, jdbcUsername, jdbcPassword));
    // 转换ID
    parameter.put(Constant.TRANSID, kTrans.getTransId());
    String transPath = kTrans.getTransPath();
    if (transPath.contains("/")) {
      int lastIndexOf = StringUtils.lastIndexOf(transPath, "/");
      String path = transPath.substring(0, lastIndexOf);
      // 转换在资源库中的路径
      parameter.put(Constant.TRANSPATH, StringUtils.isEmpty(path) ? "/" : path);
      // 转换名称
      parameter.put(Constant.TRANSNAME, transPath.substring(lastIndexOf + 1, transPath.length()));
    }
    // 用户ID
    parameter.put(Constant.USERID, kTrans.getAddUser());
    // 转换日志等级
    parameter.put(Constant.LOGLEVEL, kTrans.getTransLogLevel());
    // 转换日志的保存位置
    parameter.put(Constant.LOGFILEPATH, kettleLogFilePath);
    return parameter;
  }

  /**
   * @Title addMonitor
   * @Description 添加监控
   * @param userId 用户ID
   * @param transId 转换ID
   * @return void
   */
  private void addMonitor(Integer userId, Integer transId) {
    KTransMonitor template = new KTransMonitor();
    template.setAddUser(userId);
    template.setMonitorTrans(transId);
    KTransMonitor templateOne = kTransMonitorDao.templateOne(template);
    if (null != templateOne) {
      templateOne.setMonitorStatus(1);
      StringBuilder runStatusBuilder = new StringBuilder();
      runStatusBuilder.append(templateOne.getRunStatus()).append(",")
          .append(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"))
          .append(Constant.RUNSTATUS_SEPARATE);
      templateOne.setRunStatus(runStatusBuilder.toString());
      kTransMonitorDao.updateTemplateById(templateOne);
    } else {
      KTransMonitor kTransMonitor = new KTransMonitor();
      kTransMonitor.setMonitorTrans(transId);
      kTransMonitor.setAddUser(userId);
      kTransMonitor.setMonitorSuccess(0);
      kTransMonitor.setMonitorFail(0);
      StringBuilder runStatusBuilder = new StringBuilder();
      runStatusBuilder.append(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"))
          .append(Constant.RUNSTATUS_SEPARATE);
      kTransMonitor.setRunStatus(runStatusBuilder.toString());
      kTransMonitor.setMonitorStatus(1);
      kTransMonitorDao.insert(kTransMonitor);
    }
  }

  /**
   * @Title removeMonitor
   * @Description 移除监控
   * @param userId 用户ID
   * @param transId 转换ID
   * @return void
   */
  private void removeMonitor(Integer userId, Integer transId) {
    KTransMonitor template = new KTransMonitor();
    template.setAddUser(userId);
    template.setMonitorTrans(transId);
    KTransMonitor templateOne = kTransMonitorDao.templateOne(template);
    if (templateOne == null) {
      return;
    }
    templateOne.setMonitorStatus(2);
    StringBuilder runStatusBuilder = new StringBuilder();
    runStatusBuilder.append(templateOne.getRunStatus())
        .append(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
    templateOne.setRunStatus(runStatusBuilder.toString());
    kTransMonitorDao.updateTemplateById(templateOne);
  }
}
